package top.scauwlt.proxy;

import top.scauwlt.config.RpcServiceConfig;
import top.scauwlt.enums.RpcErrorMessageEnum;
import top.scauwlt.enums.RpcResponseEnum;
import top.scauwlt.exception.RpcException;
import top.scauwlt.factory.SingletonFactory;
import top.scauwlt.remoting.dto.RpcRequest;
import top.scauwlt.remoting.dto.RpcResponse;
import top.scauwlt.remoting.transport.client.NettyRpcClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * @Author wmm
 * @Date 2022/7/27 11:29
 */
public class RpcClientProxy implements InvocationHandler {

    private final NettyRpcClient nettyRpcClient;
    private final RpcServiceConfig rpcServiceConfig;

    public RpcClientProxy() {
        this(new RpcServiceConfig());
    }

    public RpcClientProxy(RpcServiceConfig rpcServiceConfig) {
        nettyRpcClient = SingletonFactory.getInstance(NettyRpcClient.class);
        this.rpcServiceConfig = rpcServiceConfig;
    }

    public <T> T getProxy(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcRequest rpcRequest = RpcRequest.builder()
                //随机生成UUID
                .requestId(UUID.randomUUID().toString())
                .group(rpcServiceConfig.getGroup())
                .version(rpcServiceConfig.getVersion())
                //获取定义方法的接口的名称
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .paramTypes(method.getParameterTypes())
                .parameters(args)
                .build();
        CompletableFuture<RpcResponse<Object>> future = (CompletableFuture<RpcResponse<Object>>) nettyRpcClient.sendRequest(rpcRequest);
        RpcResponse<Object> response = future.get();
        if (response == null) {
            throw new RpcException(RpcErrorMessageEnum.SERVICE_INVOCATION_FAIL, "interface name :" + rpcRequest.getInterfaceName());
        }
        if (!response.getRequestId().equals(rpcRequest.getRequestId())) {
            throw new RpcException(RpcErrorMessageEnum.REQUEST_NOT_MATCH_RESPONSE, "interface name :" + rpcRequest.getInterfaceName());
        }
        if (response.getCode() == null || !response.getCode().equals(RpcResponseEnum.SUCCESS.getCode())) {
            throw new RpcException(RpcErrorMessageEnum.SERVICE_INVOCATION_FAIL, "interface name :" + rpcRequest.getInterfaceName());
        }
        return response.getData();
    }
}
